package nl.weeaboo.sh.view;

import java.awt.Point;
import java.awt.Rectangle;

import nl.weeaboo.sh.Game;
import nl.weeaboo.sh.GameFrame;
import nl.weeaboo.sh.level.Level;
import nl.weeaboo.sh.objects.Player;

public class Camera {
	
	private Level level;
	
	private Point position;
	private Point targetPoint;
	private float scale;
	
	private Point difference;
	private Point differenceFrames;
	
	public Camera(Game game, Level level) {
		this.level = level;
		
		reset();
	}
	
	//Functions
	public void reset() {
		position = new Point(0, 0);
		targetPoint = null;
		scale = 1f;
		
		difference = new Point(0, 0);
		differenceFrames = new Point(0, 0);
	}
	
	public void update(Rectangle bounds) {		
		int minX = (int)Math.ceil(bounds.x + (GameFrame.defaultWidth >>> 1) / scale);
		int maxX = (int)Math.floor(bounds.x + bounds.width - (GameFrame.defaultWidth >>> 1) / scale);
		int minY = (int)Math.ceil(bounds.y + (GameFrame.defaultHeight >>> 1) / scale);
		int maxY = (int)Math.floor(bounds.y + bounds.height - (GameFrame.defaultHeight >>> 1) / scale);	
		
		Player player = level.getPlayer();		
		if (player != null) {
			//System.out.println(difference + " " + differenceFrames);
			
			double a = Math.min(30.0, Math.max(0, differenceFrames.x-30) / 3.0);
			double b = Math.min(30.0, Math.max(0, differenceFrames.y-30) / 3.0);
			targetPoint = new Point(player.getX() + (int)(player.getSpeedX() * a),
					player.getY() + (int)(player.getSpeedY() * b));
		} else {
			targetPoint = null;
			difference.x = difference.y = 0;
			differenceFrames.x = differenceFrames.y = 0;
		}
		
		if (targetPoint != null) {
			targetPoint.x = Math.max(Math.min(targetPoint.x, maxX), minX);
			targetPoint.y = Math.min(Math.max(targetPoint.y, minY), maxY);
			
			int dx = targetPoint.x - getX();
			int dy = targetPoint.y - getY();
			if (Math.abs(dx) < 10) dx = dx + 10 * (int)Math.signum(dx);
			if (Math.abs(dy) < 10) dy = dy + 10 * (int)Math.signum(dy);
			move(dx/10, dy/10);
		}

		//TODO: Instead of simply pushing the camera within bounds in a single frame, we
		//      can also just block it from going out of bounds further. That way, the camera
		//      will eventually move back into bounds. <- basically gives a more smooth transition.
		//NOTE: Lol, commenting out these two lines is already an acceptable solution
		//position.x = Math.max(Math.min(position.x, maxX), minX);
		//position.y = Math.min(Math.max(position.y, minY), maxY);

		if (targetPoint != null) {
			if (targetPoint.x > minX && targetPoint.x < maxX) {
				int oldDiffX = difference.x;
				difference.x = targetPoint.x - getX();
				if (Math.abs(difference.x) < Level.tileSize) {
					difference.x = 0;
					differenceFrames.x = 0;
				}
				differenceFrames.x = (difference.x * oldDiffX > 0 ? differenceFrames.x+1 : differenceFrames.x-1);
				if (differenceFrames.x < 0) differenceFrames.x = 0;
			}
			if (targetPoint.y > minY && targetPoint.y < maxY) {
				int oldDiffY = difference.y;
				difference.y = targetPoint.y - getY();
				if (Math.abs(difference.y) < Level.tileSize) {
					difference.y = 0;
					differenceFrames.y = 0;
				}
				differenceFrames.y = (difference.y * oldDiffY > 0 ? differenceFrames.y+1 : differenceFrames.y-1);
				if (differenceFrames.y < 0) differenceFrames.y = 0;
			}
		}
	}

	
	//Getters
	public int getX() { return position.x; }
	public int getY() { return position.y; }
	public boolean isPlayerTarget() { return true; }
	public float getScale() { return scale; }
	
	//Setters
	public void setX(int tx) { position.x = tx; }
	public void setY(int ty) { position.y = ty; }
	public void setXY(int x, int y) {
		position.x = x;
		position.y = y;
	}
	
	public void move(int dx, int dy) {
		position.x += dx;
		position.y += dy;
	}
	
	public void setTarget(int x, int y) {
		setTarget(new Point(x, y));
	}
	public void setTarget(Point p) {
		targetPoint = p;
	}
	public void setScale(float s) {
		/*
		int w2 = GameFrame.defaultWidth >> 1;
		int h2 = GameFrame.defaultHeight >> 1;
		int tx = Math.round(s * w2 - scale * w2);
		int ty = Math.round(s * h2 - scale * h2);		
		position.translate(tx, ty);
		*/
		
		scale = s;
	}
	
}
